﻿namespace JoinBox.MathEx.TSP;

using JoinBox.MathEx;
using System;
using System.Collections.Generic;
using System.Diagnostics;

// https://github.com/7lb/TSP

public class 遗传算法解TSP
{
    public class GeneticInfo : GeneticInfoBasal
    {
#pragma warning disable CA2211 // 非常量字段应当不可见
        /// <summary>
        /// 变异概率
        /// </summary>
        public static new double MutateProbability;
        public static new SelectMode SelectMode;
#pragma warning restore CA2211 // 非常量字段应当不可见

        public GeneticInfo()
        {
            Iterations        = -1;
            ChromosomeNumber  = 20;
            MutateProbability = 0.04;
            EvolveTime        = 2_000;
            SelectMode        = SelectMode.Roulette;
        }
    }
    public static void TestCmd()
    {
        new TSP.GeneticAlgorithm<GeneticInfo>(null, (gen, tour) =>
        {
            Console.WriteLine($"当前代数:   {gen}\n" +
                              $"当前适应度: {tour?.Fitness}\n" +
                              $"当前距离:   {tour?.Distance}\n");
            return false;
        }).Bulid();
    }
}



public class GeneticAlgorithm<TGeneticInfo> // : SelectModeMethod, GeneticMethod
     where TGeneticInfo : GeneticInfoBasal, new()
{
    readonly Func<int, Tour, bool> _Func;
    readonly TGeneticInfo _Info;
    Colony<TGeneticInfo>? _Colony;

    /// <summary>
    /// 遗传算法旅行商最短距离
    /// </summary>
    /// <param name="pts">点集</param>
    /// <param name="func">每次循环到最佳时候执行:人口代数,路线,bool==终止循环</param>
    /// <param name="info">遗传参数信息根据项目调整</param>
    public GeneticAlgorithm(List<PointV>? pts,
                            Func<int, Tour, bool> func,
                            TGeneticInfo? info = null)
    {
        _Func = func ?? throw new ArgumentNullException(nameof(func));
        _Info = info ?? new TGeneticInfo();
        Init(pts);
    }

    void Init(List<PointV>? pts)
    {
        // 初始化线路(旅行线路)
        Tour tour;
        if (pts is null)
            tour = Tour.BuildRandom(40);// 随机创建,用于测试
        else
            tour = Tour.Build(pts);

        // 初始化集群(旅行商队伍)
        List<Tour> tmp = new();
        for (int i = 0; i < tour.Citys.Count; ++i)
            tmp.Add(tour.Shuffle());
        _Colony = new Colony<TGeneticInfo>(tmp, _Info);
    }

    public void Bulid()
    {
        var stopwatch = new Stopwatch();
        double oldMutpro = _Info.MutateProbability;

        int gen = 0;        // 第几代
        bool better = true; // 更好时候的标记
        while (true)
        {
            if (_Info.Iterations != -1 && gen > _Info.Iterations)
                break;

            if (better)
            {
                if (_Colony is not null)
                {
                    // 这里可以把集群抽出去
                    var tour = _Colony.FindBest();
                    if (tour is not null)
                    {
                        if (_Func.Invoke(gen, tour))
                            break;
                    }
                }
                if (_Info.EvolveTime != -1)
                {
                    stopwatch.Reset();
                    stopwatch.Start();
                }
            }

            if (_Info.EvolveTime != -1)
            {
                // 死循环就会直到 代数 溢出,更好出最优解.
                // 最后一次没反应时候执行:当时间超 EvolveTime,变异概率叠加,
                // 1/MutateProbability==CC,CC* EvolveTime ==卡住x秒设定终止(加速停止)
                if (stopwatch.ElapsedMilliseconds > _Info.EvolveTime)
                {
                    _Info.MutateProbability += oldMutpro;
                    if (_Info.MutateProbability > 1)
                        break;
                    stopwatch.Reset();
                    stopwatch.Start();
                }
            }

            better = false;
            if (_Colony is not null)
            {
                var oldFit = _Colony.FitMax;
                _Colony = _Colony.Evolve(_Info.ChromosomeNumber);
                if (_Colony.FitMax > oldFit)
                    better = true;
            }
            gen++;
        }
    }
}